package com.xi.jetcomposedemo.activity

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CropSquare
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.Event
import androidx.compose.material.icons.filled.PrivacyTip
import androidx.compose.material.icons.filled.RestoreFromTrash
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import com.xi.jetcomposedemo.R
import com.xi.jetcomposedemo.ui.compose.AppSkeleton
import com.xi.jetcomposedemo.ui.theme.Gray100
import kotlinx.coroutines.launch
import java.util.UUID
import kotlin.random.Random

class TestComposeStateActivity : ComponentActivity() {
    private val todoViewModel by viewModels<TodoViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppSkeleton {
                initTodoScreen()
            }
        }
    }

    @Composable
    private fun initTodoScreen() {
        TodoScreen(
            items = todoViewModel.todoItems,
            currentEditing = todoViewModel.currentEditItem,
            onAddItem = todoViewModel::addTodoItem,
            onRemoveItem = todoViewModel::removeItem,
            onStartEdit = todoViewModel::onEditItemSelected,
            onEditItemChange = todoViewModel::onEditItemChange,
            onEditDone = todoViewModel::onEditDone
        )
    }

    @Composable
    private fun TodoScreen(
        items: List<TodoItem>,
        currentEditing: TodoItem?,
        onAddItem: (TodoItem) -> Unit,
        onRemoveItem: (TodoItem) -> Unit,
        onStartEdit: (TodoItem) -> Unit,
        onEditItemChange: (TodoItem) -> Unit,
        onEditDone: () -> Unit,
        modifier: Modifier = Modifier,
    ) {
        Column(
            modifier
                .fillMaxHeight()
                .background(Gray100)
        ) {
            // 显示输入框
            val addItemMode = currentEditing == null
            val state = rememberLazyListState()
            // 多行
            LazyColumn(
                modifier = Modifier.weight(1F),
                state = state,
                contentPadding = PaddingValues(top = 8.dp)
            ) {
                items(items) { todo ->
                    if (currentEditing?.id != todo.id) {
                        TodoItem(
                            todo,
                            onItemClicked = { onStartEdit(it) },
                            modifier = Modifier.fillParentMaxWidth()
                        )
                    } else {
                        TodoItemInlineEditor(
                            item = todo,
                            onEditItemChange = onEditItemChange,
                            onEditDone = onEditDone,
                            onRemoveItem = { onRemoveItem(todo) }
                        )
                    }
                }
            }

            TodoItemInputBackground(elevate = true, Modifier.fillMaxWidth()) {
                if (addItemMode) {
                    val coroutineScope = rememberCoroutineScope()
                    TodoItemEntryInput {
                        onAddItem(it)
                        coroutineScope.launch { state.animateScrollToItem((todoViewModel.todoItems.size - 1).coerceAtLeast(0)) }
                    }
                } else {
                    Text(
                        text = "Editing item",
                        style = MaterialTheme.typography.titleMedium,
                        textAlign = TextAlign.Center,
                        modifier = Modifier
                            .align(Alignment.CenterVertically)
                            .padding(16.dp)
                            .fillMaxWidth()
                    )
                }
            }
        }
    }

    @Composable
    private fun TodoItem(
        item: TodoItem,
        onItemClicked: (TodoItem) -> Unit,
        modifier: Modifier = Modifier
    ) {
        Row(
            modifier = modifier
                .clickable { onItemClicked(item) }
                .padding(horizontal = 16.dp, vertical = 8.dp),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(text = item.task)
            // 具有内部状态的可组合项，不易重复使用，也更难测试，最佳实践是将状态提升，以保持可组合项无状态化。
            val iconAlpha = remember(item.id) {
                randomAlpha()
            }
            Icon(
                imageVector = item.icon.imageVector,
                contentDescription = stringResource(id = item.icon.contentDescription),
                tint = LocalContentColor.current.copy(alpha = iconAlpha)
            )
        }
    }

    @Composable
    private fun TodoItemInputBackground(
        elevate: Boolean,
        modifier: Modifier = Modifier,
        content: @Composable RowScope.() -> Unit
    ) {
        // 帧动画的形式展现Surface底部的阴影
        val animatedElevation by animateDpAsState(if (elevate) 1.dp else 0.dp, TweenSpec(500), label = "")
        Surface(
            modifier = modifier,
            color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.05f),
            shadowElevation = animatedElevation,
            shape = RectangleShape,
        ) {
            Row(
                modifier = Modifier.animateContentSize(animationSpec = TweenSpec(300)),
                content = content
            )
        }
    }

    /**
     * 当点击TodoItem列表中的条目时，弹出该输入框，用于修改被选中的条目。
     * 编辑todoItem输入框。
     */
    @Composable
    private fun TodoItemInlineEditor(
        item: TodoItem,
        onEditItemChange: (TodoItem) -> Unit,
        onEditDone: () -> Unit,
        onRemoveItem: () -> Unit,
    ) {
        TodoItemInput(
            text = item.task,
            onTextChange = { onEditItemChange(item.copy(task = it)) },
            selectedIcon = item.icon,
            onIconChange = { onEditItemChange(item.copy(icon = it)) },
            iconsVisible = true,
            submit = onEditDone
        ) {
            // 保存和删除两个图标
            Row {
                val shrinkButtons = Modifier.widthIn(20.dp)
                TextButton(onClick = onEditDone, modifier = shrinkButtons) {
                    Text(
                        text = "\uD83D\uDCBE",
                        textAlign = TextAlign.End,
                    )
                }

                TextButton(onClick = onRemoveItem, modifier = shrinkButtons) {
                    Text(
                        text = "X",
                        textAlign = TextAlign.End,
                    )
                }
            }
        }
    }

    /**
     * 新增todoItem输入框
     */
    @Composable
    private fun TodoItemEntryInput(onInputComplete: (TodoItem) -> Unit) {
        val (text, setText) = remember { mutableStateOf("") }
        val (icon, setIcon) = remember { mutableStateOf(TodoIcon.Default) }
        val iconsVisible = text.isNotBlank()
        val submit = {
            onInputComplete(TodoItem(text, icon))
            setText("")
        }
        TodoItemInput(
            text = text,
            onTextChange = setText,
            selectedIcon = icon,
            onIconChange = setIcon,
            iconsVisible = iconsVisible,
            submit = submit,
        ) {
            TodoEditButton(
                onClick = submit,
                text = "Add",
                enabled = !text.isNullOrBlank()
            )
        }
    }

    @Composable
    private fun TodoItemInput(
        text: String,
        onTextChange: (String) -> Unit,
        selectedIcon: TodoIcon,
        onIconChange: (TodoIcon) -> Unit,
        iconsVisible: Boolean,
        submit: () -> Unit,
        buttonSlot: @Composable () -> Unit,
    ) {

        Column {
            Row(
                Modifier
                    .padding(horizontal = 16.dp)
                    .padding(top = 16.dp)
            ) {
                TodoInputText(
                    text = text,
                    onTextChange = onTextChange,
                    modifier = Modifier
                        .weight(1f)
                        .padding(end = 8.dp),
                    onImeAction = submit
                )

                Spacer(modifier = Modifier.width(8.dp))

                Box(modifier = Modifier.align(Alignment.CenterVertically)) {
                    buttonSlot()
                }
            }

            if (iconsVisible) {
                AnimatedIconRow(
                    selectedIcon = selectedIcon,
                    Modifier.padding(top = 8.dp),
                    onIconChange = onIconChange
                )
            } else {
                Spacer(modifier = Modifier.height(16.dp))
            }
        }
    }

    // 输入框
    @OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
    @Composable
    private fun TodoInputText(
        text: String,
        onTextChange: (String) -> Unit,
        modifier: Modifier = Modifier,
        onImeAction: () -> Unit = {}
    ) {
        val keyboardController = LocalSoftwareKeyboardController.current
        TextField(
            value = text,
            onValueChange = onTextChange,
            colors = TextFieldDefaults.textFieldColors(containerColor = Color.White),
            maxLines = 1,
            modifier = modifier,
            // 配置软键盘
            keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
            keyboardActions = KeyboardActions(onDone = {
                onImeAction()
                // 隐藏键盘
                keyboardController?.hide()
            })
        )
    }

    @Composable
    private fun TodoEditButton(
        onClick: () -> Unit,
        text: String,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
    ) {
        TextButton(
            onClick = onClick,
            shape = CircleShape,
            colors = ButtonDefaults.buttonColors(),
            modifier = modifier,
            enabled = enabled
        ) {
            Text(text = text)
        }
    }

    @Composable
    private fun AnimatedIconRow(
        selectedIcon: TodoIcon,
        modifier: Modifier = Modifier,
        visible: Boolean = true,
        onIconChange: (TodoIcon) -> Unit,
    ) {
        val enter = remember { fadeIn(animationSpec = TweenSpec(300, easing = FastOutLinearInEasing)) }
        val exit = remember { fadeOut(animationSpec = TweenSpec(100, easing = FastOutSlowInEasing)) }
        Box(modifier = modifier.defaultMinSize(minHeight = 16.dp)) {
            AnimatedVisibility(
                visible = visible,
                enter = enter,
                exit = exit
            ) {
                Row() {
                    for (todoIcon in TodoIcon.values()) {
                        SelectableIconButton(
                            todoIcon,
                            onIconSelected = { onIconChange(todoIcon) },
                            isSelected = todoIcon == selectedIcon
                        )
                    }
                }
            }
        }
    }

    @Composable
    private fun SelectableIconButton(
        icon: TodoIcon,
        onIconSelected: () -> Unit,
        isSelected: Boolean,
        modifier: Modifier = Modifier
    ) {
        val tint = if (isSelected) {
            MaterialTheme.colorScheme.primary
        } else {
            MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6F)
        }
        TextButton(
            onClick = { onIconSelected() },
            shape = CircleShape,
            modifier = modifier
        ) {
            Column {
                Icon(
                    imageVector = icon.imageVector,
                    contentDescription = stringResource(id = icon.contentDescription),
                    tint = tint
                )
                if (isSelected) {
                    Box(
                        Modifier
                            .padding(top = 3.dp)
                            .width(icon.imageVector.defaultWidth)
                            .height(1.dp)
                            .background(tint)

                    ) {

                    }
                } else {
                    Spacer(modifier = Modifier.height(4.dp))
                }
            }
        }
    }

    private fun randomAlpha(): Float {
        return Random.nextFloat().coerceIn(0.3f, 0.9f)
    }

//    @Preview(showBackground = true)
//    @Composable
//    fun preViewScreen() {
//        val items = listOf(
//            TodoItem("Learn compose", TodoIcon.Event),
//            TodoItem("Take the codelab"),
//            TodoItem("Apply state", TodoIcon.Done),
//            TodoItem("Build dynamic UIs", TodoIcon.Square)
//        )
//        TodoScreen(
//            items = items,
//            onAddItem = {},
//            onRemoveItem = {}
//        )
//    }
}

data class TodoItem(
    val task: String,
    val icon: TodoIcon = TodoIcon.Default,
    val id: UUID = UUID.randomUUID()
) {
    companion object {
        private val todoTasks = listOf(
            "Learn compose",
            "Learn state",
            "Build dynamic UIs",
            "Learn Unidirectional Data Flow",
            "Integrate LiveData",
            "Integrate ViewModel",
            "Remember to savedState!",
            "Build stateless composables",
            "Use state from stateless composables"
        )

        fun genRandomTodoItem(): TodoItem {
            val icon = TodoIcon.values().random()
            return TodoItem(todoTasks.random(), icon)
        }
    }
}

enum class TodoIcon(
    val imageVector: ImageVector, @StringRes val contentDescription: Int
) {
    Square(Icons.Default.CropSquare, R.string.cd_expand),
    Done(Icons.Default.Done, R.string.cd_done), Event(Icons.Default.Event, R.string.cd_event),
    Privacy(Icons.Default.PrivacyTip, R.string.cd_privacy),
    Trash(Icons.Default.RestoreFromTrash, R.string.cd_restore);

    companion object {
        val Default = Square
    }
}

/**
 * 状态容器
 */
class TodoViewModel : ViewModel() {
    var todoItems = mutableStateListOf<TodoItem>()
        private set
    // 当前正在编辑的item的位置
    private var currentEditPosition by mutableStateOf(-1)
    // 当前正在编辑的item对象
    val currentEditItem: TodoItem?
        get() = todoItems.getOrNull(currentEditPosition)

    fun addTodoItem(item: TodoItem) {
        todoItems.add(item)
    }

    fun removeItem(item: TodoItem) {
        todoItems.remove(item)
        onEditDone()
    }

    fun onEditDone() {
        currentEditPosition = -1
    }

    fun onEditItemSelected(item: TodoItem) {
        currentEditPosition = todoItems.indexOf(item)
    }

    fun onEditItemChange(item: TodoItem) {
        if (currentEditItem?.id == item.id) {
            todoItems[currentEditPosition] = item
        }
    }
}